﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace Fortuitus.Core
{
    public static class VectorStatisticExtensions
    {
        /// <summary>
        /// Checks whether an Vector is empty or just contains missing values (NaN).
        /// </summary>
        /// <param name="vector">The input vector of numbers.</param>
        /// <returns>An value indicating whether the Vector is empty or consists of missing values only.</returns>
        public static bool IsEmptyOrHasNoValues(this IVector vector)
        {
            bool hasValues = false;
            foreach (double number in vector)
            {
                if (!double.IsNaN(number))
                {
                    hasValues = true;
                    break;
                }
            }
            return !hasValues;
        }

        /// <summary>
        /// Reverses an existing vector.
        /// </summary>
        /// <param name="vector">The Vector to be reversed</param>
        /// <returns>A Vector View that returns the elements in reversed order/ </returns>
        public static IVectorView Reverse(this IVector vector)
        {
            var length = vector.Length;
            MaskedVectorView ret = new MaskedVectorView(vector, vector.Select(x => { length -= 1; return length; }).ToArray());
            return ret;
        }

        /// <summary>
        /// Generates view without the missing values.
        /// </summary>
        /// <param name="vector">The input vector that may contains NaN values.</param>
        /// <returns>A viewover the input vector that contains no missing values (NaN).</returns>
        public static IVectorView MissingValueDeletion(this IVector vector)
        {
            var length = vector.Length;
            MaskedVectorView ret;
            OrderedList<int> mask = new OrderedList<int>();
            for (int i = 0; i < vector.Length; i++)
            {
                if (!double.IsNaN(vector[i]))
                    mask.Add(i);
            }
            ret = new MaskedVectorView(vector, mask);
            return ret;
        }


        /// <summary>
        /// Calculates the vector of ranks of given vector.
        /// </summary>
        /// <param name="vector">The vector of corresponding ranks foreach element.</param>
        /// <returns></returns>
        public static IVector ToRanks(this IVector vector)
        {
            //sort the input vector
            List<double> sorted = (from x in vector orderby x ascending select x).ToList();
            double rank = 1;
            List<double> accumulatedRanks = new List<double>();
           // int tiecount = 0;
            //List<double> sorted = (from x in vector orderby x descending select rank++).ToList();
            //return new Vector(sorted);

            List<double> ranks = new List<double>();

            //for (int i = 0; i <= sorted.Count; i++)
            //{
            //    if (i > 0 && (i == sorted.Count || sorted[i] != sorted[i - 1]))
            //    {
            //        double avgRank = accumulatedRanks.Mean();
            //        for (int j = i - accumulatedRanks.Count; j < i; j++)
            //        {
            //            ranks.Add(avgRank);
            //        }
            //        accumulatedRanks.Clear();
            //        //  rank++;
            //    }
            //    accumulatedRanks.Add(rank);
            //    rank++;
            //}

            Dictionary<double, List<double>> numberLookup = vector.Distinct().ToDictionary(x => x, x=> new List<double>());
            for (int i = 0; i < sorted.Count; i++)
            {
                //if (!numberLookup.ContainsKey(sorted[i]))
                //    numberLookup.Add(sorted[i], new List<double>());
                numberLookup[sorted[i]].Add(i + 1);
            }

            foreach (var item in vector)
            {
                ranks.Add((numberLookup[item].Mean()));
            }
            return new Vector(ranks);

        }

    }
}
